package com.sky.exceptionhandler;

import com.sky.constant.MessageConstant;
import com.sky.exception.BaseException;
import com.sky.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {


    /**
     * 捕获业务异常
     * @param ex
     * @return
     */
    @ExceptionHandler
    public Result exceptionHandler(BaseException ex){
        log.error("异常信息：{}", ex.getMessage());
        return Result.error(ex.getMessage());
    }




    /**
     * 使用@Validated 或 @Valid 注解    检验Json类型数据
     *                                 全局异常捕获
     * @param ex
     */
    @ExceptionHandler(value= MethodArgumentNotValidException.class)
    public Result methodArgumentNotValidException(MethodArgumentNotValidException ex){
        //获取封装的异常
        List<ObjectError> allErrors = ex.getAllErrors();
        if( !CollectionUtils.isEmpty(allErrors) ) {
            String exception = allErrors.stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(";"));
            return Result.error(exception);
        }
        return Result.error(MessageConstant.PARAMETER_IS_NULL);
    }



    /**
     使用@Validated 或 @Valid 注解     校验路径拼接参数       url?name=xxx&age=xxx
     定义形参接收   形参上  未添加@RequestParam 注解
     *                                全局异常捕获
     */
    @ExceptionHandler(value= ConstraintViolationException.class)
    public Result constraintViolationException(ConstraintViolationException ex){
        //获取封装的异常
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if( !CollectionUtils.isEmpty(constraintViolations) ){
            String exception = constraintViolations.stream().map(ConstraintViolation::getMessageTemplate).collect(Collectors.joining(";"));
            return Result.error(exception);
        }
        return Result.error(MessageConstant.PARAMETER_IS_NULL);
    }



    /**
     * 使用@Validated 或 @Valid 注解    路径拼接参数 url?name=xxx&age=xxx  实体类接收参数
     *                                全局异常捕获
     */
    @ExceptionHandler(value= BindException.class)
    public Result bindException(BindException ex){
        //获取封装的异常
        BindingResult bindingResult = ex.getBindingResult();
        if(Objects.nonNull(bindingResult) && bindingResult.hasErrors()){
            String exceptionStr = bindingResult.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(";"));
            return Result.error(exceptionStr);
        }
        return Result.error(MessageConstant.PARAMETER_IS_NULL);
    }



    //@NotBlank + @RequestParam校验
    //MissingServletRequestParameterException
    @ExceptionHandler(value= MissingServletRequestParameterException.class)
    public Result missingServletRequestParameterException(MissingServletRequestParameterException ex){
        //获取封装的异常
        //org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'password' for method parameter type String is not present
        //System.out.println(ex);
        //Required request parameter 'password' for method parameter type String is not present
        //System.out.println(ex.getLocalizedMessage());
        //String
        //System.out.println(ex.getParameterType());
        //password
        //System.out.println(ex.getParameterName());
        //Required request parameter 'password' for method parameter type String is not present
        //System.out.println(ex.getMessage());

        String parameterType = ex.getParameterType();
        String parameterName = ex.getParameterName();
        return Result.error(parameterType + " " + parameterName +" is null");
    }




    /**
     * 数据库
     *      唯一字段重复插入异常
     * @param ex
     */
    @ExceptionHandler(value = SQLIntegrityConstraintViolationException.class)
    public Result sQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException ex) {
        String errMsg = ex.getMessage();
        //System.out.println(errMsg);
        if (errMsg.contains("Duplicate entry")) {
            String[] errArr = ex.getMessage().split(" ");
            return Result.error("字段 " + errArr[2] + " 已存在");
        }
        return Result.error(MessageConstant.UNKNOWN_ERROR);
    }




}
